﻿//------------------------------------------------------------------------------
//  Namespace: FruitVentDesign.Controls.DatePicker
//  
//  Function： N/A
//  Name： DatePickerDropdown
//  
//  Ver       Time                     Author
//  0.10      2023/2/14 10:00:51                   Benedict Deng
//
//  Description:
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------

using FruitVentDesign.Enums;
using FruitVentDesign.Models;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;

namespace FruitVentDesign.Controls
{
    public class DateTimePickerDropdown : Control
    {
        #region PickerProperty 选择器类型
        /// <summary>
        /// 选择器类型
        /// </summary>
        public static readonly DependencyProperty PickerProperty = DependencyProperty.Register(
            "Picker", typeof(DatePickerType), typeof(DateTimePickerDropdown), new FrameworkPropertyMetadata(DatePickerType.DateTime));

        public DatePickerType Picker
        {
            get { return (DatePickerType)GetValue(PickerProperty); }
            set { SetValue(PickerProperty, value); }
        }

        public static DatePickerType GetPicker(DependencyObject d)
        {
            return (DatePickerType)d.GetValue(PickerProperty);
        }

        public static void SetPicker(DependencyObject obj, DatePickerType value)
        {
            obj.SetValue(PickerProperty, value);
        }
        #endregion

        private DateTime? _dateTime = null;
        private readonly List<string> _hours = new List<string>();
        private readonly List<string> _minuteOrSeconds = new List<string>();

        public event EventHandler DateTimeChanged;

        public DateTimePickerDropdown(DateTime? Text)
        {
            for (int i = 0; i < 24; i++)
            {
                _hours.Add(i.ToString().PadLeft(2, '0'));
            }

            for (int i = 0; i < 60; i++)
            {
                _minuteOrSeconds.Add(i.ToString().PadLeft(2, '0'));
            }
            _dateTime = Text;

            Loaded += DateTimePickerDropdown_Loaded;
        }

        private void DateTimePickerDropdown_Loaded(object sender, RoutedEventArgs e)
        {
            if (_calendar != null)
            {
                _calendar.DisplayMode = Picker switch
                {
                    DatePickerType.Year => CalendarMode.Decade,
                    DatePickerType.Month => CalendarMode.Year,
                    _ => CalendarMode.Month,
                };
            }
        }

        private Calendar _calendar;
        private ListBox _hoursListBox;
        private ListBox _minutesListBox;
        private ListBox _secondsListBox;
        private TextBlock _timeTextBlock;
        private Button _atthemomentButton;
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            _atthemomentButton = Template.FindName("Date_Time_Picker_At_the_Moment", this) as Button;
            _calendar = Template.FindName("Date_Time_Picker_Calendar", this) as Calendar;
            switch (Picker)
            {
                case DatePickerType.Year:
                case DatePickerType.Month:
                    if (_calendar != null)
                    {
                        _calendar.DisplayDateChanged += Calendar_DisplayDateChanged;
                        _calendar.DisplayModeChanged += Calendar_DisplayModeChanged;
                        _calendar.PreviewMouseUp += Calendar_PreviewMouseUp;
                    }
                    if (_atthemomentButton != null)
                    {
                        _atthemomentButton.Click += AtthemomentButton_Click;
                    }
                    if (_dateTime.HasValue)
                    {
                        if (_calendar != null) { 
                            _calendar.SelectedDate = _dateTime.Value; 
                            _calendar.DisplayDate = _dateTime.Value;
                        }
                    }
                    break;
                case DatePickerType.Date:
                    if (_calendar != null)
                    {
                        _calendar.SelectedDatesChanged += Calendar_SelectedDatesChanged;
                        _calendar.DisplayModeChanged += Calendar_DisplayModeChanged;
                        _calendar.PreviewMouseUp += Calendar_PreviewMouseUp;
                    }
                    if (_atthemomentButton != null)
                    {
                        _atthemomentButton.Click += AtthemomentButton_Click;
                    }
                    if (_dateTime.HasValue)
                    {
                        if (_calendar != null) { 
                            _calendar.SelectedDate = _dateTime.Value;
                            _calendar.DisplayDate = _dateTime.Value;
                        }
                    }
                    break;
                case DatePickerType.DateTime:
                    _hoursListBox = Template.FindName("Date_Time_Picker_Hours", this) as ListBox;
                    _minutesListBox = Template.FindName("Date_Time_Picker_Minutes", this) as ListBox;
                    _secondsListBox = Template.FindName("Date_Time_Picker_Seconds", this) as ListBox;
                    _timeTextBlock = Template.FindName("Date_Time_Picker_Time", this) as TextBlock;
                    if (_calendar != null)
                    {
                        _calendar.SelectedDatesChanged += Calendar_SelectedDatesChanged;
                        _calendar.PreviewMouseUp += Calendar_PreviewMouseUp;
                    }
                    if (_atthemomentButton != null)
                    {
                        _atthemomentButton.Click += AtthemomentButton_Click;
                    }
                    if (_hoursListBox != null)
                    {
                        _hoursListBox.ItemsSource = _hours;
                        _hoursListBox.SelectionChanged += HoursListBox_SelectionChanged;
                    }
                    if (_minutesListBox != null)
                    {
                        _minutesListBox.ItemsSource = _minuteOrSeconds;
                        _minutesListBox.SelectionChanged += MinutesListBox_SelectionChanged;
                    }
                    if (_secondsListBox != null)
                    {
                        _secondsListBox.ItemsSource = _minuteOrSeconds;
                        _secondsListBox.SelectionChanged += SecondsListBox_SelectionChanged;
                    }

                    if (_dateTime.HasValue)
                    {
                        string hourStr = _dateTime.Value.Hour.ToString().PadLeft(2, '0');
                        string minuteStr = _dateTime.Value.Minute.ToString().PadLeft(2, '0');
                        string secondStr = _dateTime.Value.Second.ToString().PadLeft(2, '0');
                        if (_calendar != null) 
                        { 
                            _calendar.SelectedDate = _dateTime.Value;
                            _calendar.DisplayDate = _dateTime.Value;
                        }
                        if (_hoursListBox != null)
                        {
                            _hoursListBox.SelectedValue = hourStr;
                            _hoursListBox.ScrollIntoView(_hoursListBox.SelectedItem);
                        }
                        if (_minutesListBox != null)
                        {
                            _minutesListBox.SelectedValue = minuteStr;
                            _minutesListBox.ScrollIntoView(_minutesListBox.SelectedItem);
                        }
                        if (_secondsListBox != null)
                        {
                            _secondsListBox.SelectedValue = secondStr;
                            _secondsListBox.ScrollIntoView(_secondsListBox.SelectedItem);
                        }
                        if (_timeTextBlock != null)
                        {
                            _timeTextBlock.Text = $"{hourStr}:{minuteStr}:{secondStr}";
                        }
                    }
                    break;
            }
        }

        /// <summary>
        /// 此刻按钮点击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void AtthemomentButton_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            DateTime now = DateTime.Now;
            switch (Picker)
            {
                case DatePickerType.Year:
                case DatePickerType.Month:
                    if (_calendar != null)
                    {
                        _calendar.DisplayDate = now;
                        _calendar.SelectedDate = now;
                    }
                    break;
                case DatePickerType.Date:
                    if (_calendar != null)
                    {
                        _calendar.SelectedDate = now;
                    }
                    break;
                case DatePickerType.DateTime:
                    if (_calendar != null)
                    {
                        _calendar.SelectedDate = now;
                    }
                    string hourStr = now.Hour.ToString().PadLeft(2, '0');
                    string minuteStr = now.Minute.ToString().PadLeft(2, '0');
                    string secondStr = now.Second.ToString().PadLeft(2, '0');
                    if (_hoursListBox != null)
                    {
                        _hoursListBox.SelectedValue = hourStr;
                        _hoursListBox.ScrollIntoView(_hoursListBox.SelectedItem);
                    }
                    if (_minutesListBox != null)
                    {
                        _minutesListBox.SelectedValue = minuteStr;
                        _minutesListBox.ScrollIntoView(_minutesListBox.SelectedItem);
                    }
                    if (_secondsListBox != null)
                    {
                        _secondsListBox.SelectedValue = secondStr;
                        _secondsListBox.ScrollIntoView(_secondsListBox.SelectedItem);
                    }
                    if (_timeTextBlock != null)
                    {
                        _timeTextBlock.Text = $"{hourStr}:{minuteStr}:{secondStr}";
                    }
                    break;
            }
        }

        /// <summary>
        ///  日历显示日期发生改变
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Calendar_DisplayDateChanged(object sender, CalendarDateChangedEventArgs e)
        {
            DateTime? cdt = DateTime.Parse((sender as Calendar).DisplayDate.ToString());

            if (cdt.HasValue)
            {
                DateTime? odt = _dateTime;
                if (odt.HasValue)
                {
                    switch (Picker)
                    {
                        case DatePickerType.Year:
                            _dateTime = new DateTime(cdt.Value.Year, 1, 1);
                            break;
                        case DatePickerType.Month:
                            _dateTime = new DateTime(cdt.Value.Year, cdt.Value.Month, 1);
                            break;
                    }
                }
                else
                {
                    switch (Picker)
                    {
                        case DatePickerType.Year:
                            _dateTime = new DateTime(cdt.Value.Year, 1, 1);
                            break;
                        case DatePickerType.Month:
                            _dateTime = new DateTime(cdt.Value.Year, cdt.Value.Month, 1);
                            break;
                    }
                }
                DateTimeChanged?.Invoke(this, new DateTimeChangeEventArgs(_dateTime));
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <exception cref="NotImplementedException"></exception>
        private void Calendar_SelectedDatesChanged(object sender, SelectionChangedEventArgs e)
        {
            DateTime? cdt = DateTime.Parse((sender as Calendar).SelectedDate.ToString());

            if (cdt.HasValue)
            {
                DateTime? odt = _dateTime;
                if (odt.HasValue)
                {
                    switch (Picker)
                    {
                        case DatePickerType.Date:
                            _dateTime = new DateTime(cdt.Value.Year, cdt.Value.Month, cdt.Value.Day);
                            break;
                        case DatePickerType.DateTime:
                            _dateTime = new DateTime(cdt.Value.Year, cdt.Value.Month, cdt.Value.Day, odt.Value.Hour, odt.Value.Minute, odt.Value.Second);
                            break;
                    }
                }
                else
                {
                    switch (Picker)
                    {
                        case DatePickerType.Date:
                            _dateTime = new DateTime(cdt.Value.Year, cdt.Value.Month, cdt.Value.Day);
                            break;
                        case DatePickerType.DateTime:
                            _dateTime = new DateTime(cdt.Value.Year, cdt.Value.Month, cdt.Value.Day, 0, 0, 0);
                            _hoursListBox.SelectedValue = "00";
                            _minutesListBox.SelectedValue = "00";
                            _secondsListBox.SelectedValue = "00";
                            _timeTextBlock.Text = $"00:00:00";
                            break;
                    }
                }
                DateTimeChanged?.Invoke(this, new DateTimeChangeEventArgs(_dateTime));
            }
        }

        /// <summary>
        /// 日历控件切换模式的控制
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <exception cref="NotImplementedException"></exception>
        private void Calendar_DisplayModeChanged(object sender, CalendarModeChangedEventArgs e)
        {
            switch (Picker)
            {
                case DatePickerType.Year:
                    if (!e.NewMode.Equals(CalendarMode.Decade))
                    {
                        _calendar.DisplayMode = CalendarMode.Decade;
                    }
                    break;
                case DatePickerType.Month:
                    if (e.NewMode.Equals(CalendarMode.Month))
                    {
                        _calendar.DisplayMode = CalendarMode.Year;
                    }
                    break;
                case DatePickerType.Date:
                case DatePickerType.DateTime:
                default:
                    break;
            }
        }

        /// <summary>
        /// 日历控件鼠标事件抬起
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Calendar_PreviewMouseUp(object sender, MouseButtonEventArgs e)
        {
            if (Mouse.Captured is CalendarItem)
            {
                Mouse.Capture(null);
            }
        }

        /// <summary>
        /// 小时列表选中发生改变
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void HoursListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ListBox listBox = sender as ListBox;
            string str = (string)listBox.SelectedValue;
            if (!string.IsNullOrEmpty(str))
            {
                DateTime? odt = _dateTime;
                if (odt.HasValue)
                {
                    _dateTime = new DateTime(odt.Value.Year, odt.Value.Month, odt.Value.Day, int.Parse(str), odt.Value.Minute, odt.Value.Second);
                }
                else
                {
                    DateTime now = DateTime.Now;
                    _dateTime = new DateTime(now.Year, now.Month, now.Day, int.Parse(str), 0, 0);
                    _calendar.SelectedDate = _dateTime.Value;
                    _minutesListBox.SelectedValue = "00";
                    _secondsListBox.SelectedValue = "00";
                    _timeTextBlock.Text = $"{str}:00:00";
                }
                DateTimeChanged?.Invoke(this, new DateTimeChangeEventArgs(_dateTime));
            }
        }

        /// <summary>
        /// 分钟列表选中发生改变
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MinutesListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ListBox listBox = sender as ListBox;
            string str = (string)listBox.SelectedValue;
            if (!string.IsNullOrEmpty(str))
            {
                DateTime? odt = _dateTime;
                if (odt.HasValue)
                {
                    _dateTime = new DateTime(odt.Value.Year, odt.Value.Month, odt.Value.Day, odt.Value.Hour, int.Parse(str), odt.Value.Second);
                }
                else
                {
                    DateTime now = DateTime.Now;
                    _dateTime = new DateTime(now.Year, now.Month, now.Day, 0, int.Parse(str), 0);
                    _calendar.SelectedDate = _dateTime.Value;
                    _hoursListBox.SelectedValue = "00";
                    _secondsListBox.SelectedValue = "00";
                    _timeTextBlock.Text = $"00:{str}:00";
                }
                DateTimeChanged?.Invoke(this, new DateTimeChangeEventArgs(_dateTime));
            }
        }

        /// <summary>
        /// 秒钟列表选中发生改变
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SecondsListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ListBox listBox = sender as ListBox;
            string str = (string)listBox.SelectedValue;
            if (!string.IsNullOrEmpty(str))
            {
                DateTime? odt = _dateTime;
                if (odt.HasValue)
                {
                    _dateTime = new DateTime(odt.Value.Year, odt.Value.Month, odt.Value.Day, odt.Value.Hour, odt.Value.Minute, int.Parse(str));
                }
                else
                {
                    DateTime now = DateTime.Now;
                    _dateTime = new DateTime(now.Year, now.Month, now.Day, 0, 0, int.Parse(str));
                    _calendar.SelectedDate = _dateTime.Value;
                    _hoursListBox.SelectedValue = "00";
                    _minutesListBox.SelectedValue = "00";
                    _timeTextBlock.Text = $"00:00:{str}";
                }
                DateTimeChanged?.Invoke(this, new DateTimeChangeEventArgs(_dateTime));
            }
        }
    }
}
